package com.zlyx.easy.drools.builder;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import com.zlyx.easy.core.app.AppUtils;
import com.zlyx.easy.core.reflect.ClassBody;
import com.zlyx.easy.core.utils.ClassUtils;
import com.zlyx.easy.core.utils.FileUtils;
import com.zlyx.easy.core.utils.StringUtils;
import com.zlyx.easy.drools.reader.DroolsReader;

/**
 * 规则构建工具
 *
 * @Author 赵光
 * @Desc RuleBuilder
 * @Date 2020年5月30日
 */
public class RuleBuilder {

	public static String RULEBODY = "${PACKAGE}\n\n${HEADER}\nrule \"$rule_name\"\nwhen\n    ${WHEN}\nthen\n\n    ${THEN}\nend";

	/**
	 * 实例化规则构建器
	 *
	 * @return
	 */
	public static RuleBody newBuilder() {
		return newBuilder(null);
	}

	/**
	 * 实例化规则构建器
	 *
	 * @param name 规则名称
	 * @return
	 */
	public static RuleBody newBuilder(String name) {
		return newBuilder(name, null);
	}

	/**
	 * 实例化规则构建器
	 *
	 * @param name 规则名称
	 * @param when 规则条件
	 * @return
	 */
	public static RuleBody newBuilder(String name, String when) {
		return newBuilder(name, when, null);
	}

	/**
	 * 实例化规则构建器
	 *
	 * @param name 规则名称
	 * @param when 规则条件
	 * @param then 规则内容
	 * @return
	 */
	public static RuleBody newBuilder(String name, String when, String then) {
		return new RuleBody().name(name).when(when).then(then);
	}

	/**
	 * 实例化规则构建器(将java类指定方法转化为规则)
	 *
	 * @param name       规则名称
	 * @param when       规则条件
	 * @param cls        规则所在类
	 * @param methodName 规则所在方法
	 * @return
	 */
	public static RuleBody newBuilder(String name, String when, Class<?> cls, String methodName) throws Exception {
		return newBuilder(name, when, cls, methodName, null);
	}

	/**
	 * 实例化规则构建器(将java类指定方法转化为规则)
	 *
	 * @param name         规则名称
	 * @param when         规则条件
	 * @param cls          规则所在类
	 * @param methodName   规则所在方法
	 * @param placeholders 常量转占位符Map
	 * @return
	 * @throws Exception
	 */
	public static RuleBody newBuilder(String name, String when, Class<?> cls, String methodName,
			Map<String, String> placeholders) throws Exception {
		return new RuleBody().name(name).when(when).then(cls, methodName).placeholders(placeholders);
	}

	public static class RuleBody {

		/**
		 * 包名
		 */
		private String packageName;

		/**
		 * 文件头
		 */
		private String header;

		/**
		 * 规则名称
		 */
		private String name;

		/**
		 * 规则条件
		 */
		private String when;

		/**
		 * 规则内容
		 */
		private String then;

		/**
		 * 导入类
		 */
		private Set<String> importClass;

		/**
		 * 占位符
		 */
		private Map<String, String> placeholders;

		/**
		 * 规则属性
		 */
		private Map<String, String> props;

		public RuleBody() {
			this.packageName = "package " + AppUtils.getMainClass().getPackage().getName() + ";";
			this.importClass = new TreeSet<>();
			this.placeholders = new HashMap<>();
			this.props = new HashMap<>();
		}

		/**
		 * 设置导入类
		 *
		 * @param importClass
		 * @return
		 */
		public RuleBody importClass(Class<?>... importClass) {
			importClass(Arrays.asList(importClass));
			return this;
		}

		/**
		 * 设置导入类
		 *
		 * @param importClass
		 * @return
		 */
		public RuleBody importClass(Collection<Class<?>> importClass) {
			if (importClass != null && !importClass.isEmpty()) {
				for (Class<?> cls : importClass) {
					this.importClass.add(cls.getName());
				}
			}
			return this;
		}

		/**
		 * 包名
		 *
		 * @param packageName
		 * @return
		 */
		public RuleBody packageName(String packageName) {
			this.packageName = StringUtils.trim(packageName);
			return this;
		}

		/**
		 * 文件头
		 *
		 * @param header
		 * @return
		 */
		public RuleBody header(String header) {
			this.header = StringUtils.trim(header);
			return this;
		}

		/**
		 * 文件头
		 *
		 * @return
		 */
		public String header() {
			return header;
		}

		/**
		 * 规则名称
		 *
		 * @param name
		 * @return
		 */
		public RuleBody name(String name) {
			this.name = StringUtils.trim(name);
			return this;
		}

		/**
		 * @return the name
		 */
		public String name() {
			return name;
		}

		/**
		 * 执行上下文
		 *
		 * @param when
		 * @return
		 */
		public RuleBody when(String when) {
			this.when = StringUtils.trim(when);
			return this;
		}

		/**
		 * 将普通的java方法导入为规则
		 *
		 * @param cls        方法所在类
		 * @param methodName 方法所在方法
		 * @return
		 * @throws Exception
		 */
		public RuleBody then(Class<?> cls, String methodName) throws Exception {
			ClassBody classBody = DroolsReader.parse(cls);
			this.importClass.addAll(classBody.getImportClass());
			this.header = classBody.header();
			return then(classBody.getMethod(methodName));
		}

		/**
		 * 设置规则内容
		 *
		 * @param then 直接设置规则内容
		 * @return
		 */
		public RuleBody then(String then) {
			this.then = StringUtils.trim(then);
			return this;
		}

		/**
		 * @return the then
		 */
		public String then() {
			return then;
		}

		/**
		 * 将规则常量提取为$符号的引用属性(生成规则时需要设置)
		 *
		 * @param key   常量值，eg: 1111111
		 * @param value $符号的引用： $key
		 */
		public void placeholders(String key, String value) {
			this.placeholders.put(key, value);
		}

		/**
		 * 将规则常量提取为$符号的引用属性(生成规则时需要设置)
		 *
		 * @param placeholders $符号的引用,eg:{11111=$key}
		 * @return
		 */
		public RuleBody placeholders(Map<String, String> placeholders) {
			this.placeholders.putAll(placeholders);
			return this;
		}

		/**
		 * 将$符号的引用属性替换为规则常量(验证规则时需要设置)
		 *
		 * @param key   $符号的引用： key
		 * @param value 常量值，eg: 1111111
		 */
		public void props(String key, String value) {
			this.props.put(key, value);
		}

		/**
		 * 将$符号的引用属性替换为规则常量(验证规则时需要设置)
		 *
		 * @param props ,eg:{$key=11111}
		 */
		public void props(Map<String, String> props) {
			this.props.putAll(props);
		}

		/**
		 * @return the props
		 */
		public Map<String, String> props() {
			return props;
		}

		/**
		 * 构建规则
		 *
		 * @return
		 */
		public String build() {
			if (header == null) {
				header = "";
			}
			String importString = "";
			if (!importClass.isEmpty()) {
				for (String clsName : importClass) {
					if (!header.contains(clsName) && clsName.contains(".") && !clsName.contains("java.lang")) {
						if (clsName.contains("import")) {
							importString += clsName;
						} else {
							importString += "import " + clsName + ";\n";
						}
					}
				}
			}
			then = StringUtils.replaceAll(then, placeholders);
			return RULEBODY.replace("${PACKAGE}", packageName).replace("${HEADER}", importString + header)
					.replace("${WHEN}", when).replace("${THEN}", then);
		}

		@Override
		public String toString() {
			return build();
		}

		/**
		 * 写出为java文件
		 *
		 * @return
		 * @throws Exception
		 */
		public String writeAsFile() throws Exception {
			return writeAsFile(false);
		}

		/**
		 * 写出为文件
		 *
		 * @param append 是否追加到文件尾
		 * @return
		 * @throws Exception
		 */
		public String writeAsFile(boolean append) throws Exception {
			String path = ClassUtils.getPath() + "\\src\\main\\java\\" + packageName.replace(".", "\\");
			return FileUtils.writeAsFile(path, name + ".java", build(), append);
		}

	}

}
